using System;
using System.BusinessObjects.Data;
using System.BusinessObjects.With;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Blazing.BusinessObjects.Cms;
using Blazing.BusinessObjects.Queries;
using Blazing.BusinessObjects.Tagging;
using NHibernate;

namespace Blazing.WebFacade
{
    [System.ComponentModel.DataObject]
    public class TaggingController
    {
        #region Tag

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Delete, true)]
        public void DeleteTag(Tag tag)
        {
            tag.Delete();
            tag.Save();
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Insert, true)]
        public int NewTag(Tag tag)
        {
            tag.Save();
            return tag.ID;
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, true)]
        public Tag UpdateTag(Tag tag)
        {
            Tag.Evict(tag.ID);
            Tag update = Tag.Load(tag.ID);
            With.Transaction.Execute(delegate
             {
                 update.Name = tag.Name;
                 update.Slug = tag.Slug;                 
                 update.Save();
             });
            return update;
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
        public IList<Tag> GetTags()
        {
            return Tag.Search();
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
        public IList<Tag> GetTags(string name)
        {
            return Tag.Search(QrySearchTags.Query(name));
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
        public IList<Tag> GetTags(int taxonomyId)
        {
            return Tag.Search(QrySearchTaxonomyTagsByTaxonomy.Query(taxonomyId));
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select)]
        public IList<Tag> GetTagsLike(string name, int max)
        {
            ICriteria qry = QrySearchTags.QueryLike(name);
            qry.SetMaxResults(max);

            return Tag.Search(qry);
        }

        public Tag GetTag(int id)
        {
            return Tag.Load(id);
        }

        #endregion

        #region Taxonomy

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Delete, true)]
        public void DeleteTaxonomy(Taxonomy taxonomy)
        {
            taxonomy.Delete();
            taxonomy.Save();
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Insert, true)]
        public int NewTaxonomy(Taxonomy taxonomy)
        {
            taxonomy.Save();
            return taxonomy.ID;
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, true)]
        public Taxonomy UpdateTaxonomy(Taxonomy taxonomy)
        {
            Taxonomy.Evict(taxonomy.ID);
            Taxonomy update = Taxonomy.Load(taxonomy.ID);
            update.Name = taxonomy.Name;
            update.Slug = taxonomy.Slug;
            update.TaxonomyType = taxonomy.TaxonomyType;            
            update.Save();
            return update;
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
        public IList<Taxonomy> GetTaxonomy()
        {
            return Taxonomy.Search();
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
        public List<Taxonomy> GetSortedTaxonomys(string sortExpression)
        {
            List<Taxonomy> list = (List<Taxonomy>)Taxonomy.Search();
            if (list != null && sortExpression != String.Empty)
            {
                string[] sortOptions = sortExpression.Split(' ');
                if (sortOptions.Length > 0)
                {
                    string order = sortOptions.Length > 1 ? sortOptions[1] : "ASC";
                    GenericObjectComparer<Taxonomy> comparer = new GenericObjectComparer<Taxonomy>(sortOptions[0], order);
                    list.Sort(comparer);
                }
            }
            return list;
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
        public IList<Taxonomy> GetTaxonomys(string name)
        {
            return Taxonomy.Search(QrySearchTaxonomys.Query(name));
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
        public Taxonomy GetTaxonomyByName(string name)
        {
            return Taxonomy.Fetch(QrySearchTaxonomys.Query(name));
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
        public IList<Taxonomy> GetTaxonomysByType(int taxonomyTypeId)
        {
            return Taxonomy.Search(QrySearchTaxonomysByType.Query(taxonomyTypeId));
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
        public IList<Taxonomy> GetTaxonomysByTagId(int tagId)
        {
            return Taxonomy.Search(QrySearchTaxonomyTagsByTag.Query(tagId));
        }

        public Taxonomy GetTaxonomy(int id)
        {
            return Taxonomy.Load(id);
        }

        [DataObjectMethodAttribute(DataObjectMethodType.Select)]
        public IList<TaxonomyType> GetTaxonomyTypes()
        {
            return TaxonomyType.Search();
        }

        #endregion   

        #region Process Taxonomy Tags
        public IList<TaxonomyTag> ProcessTagList(Taxonomy taxonomy, TaxonomyTag parent, IList<Tag> tags, bool allowAdding)
        {
            //Find or save taxonomy tags
            List<TaxonomyTag> saveTaxTags = new List<TaxonomyTag>();

            foreach (Tag tag in tags)
            {
                TaxonomyTag foundTag = GetTaxonomyTag(taxonomy.ID, tag.ID);
                if (foundTag == null && allowAdding)
                {
                    foundTag = new TaxonomyTag
                    {
                        Tag=tag,
                        Taxonomy=taxonomy,
                        Description=taxonomy.Name + " " + tag.Name,
                        Slug=UrlHelper.FormatFriendly(taxonomy.Name + "-" + tag.Name),
                        ParentTaxonomyTag=parent,
                        IsSelectable = true,
                        IsVisible = true                        
                    };
                    taxonomy.TaxonomyTags.Add(foundTag);
                    foundTag.Save(SaveMode.Flush);
                }
                if(foundTag != null)
                    saveTaxTags.Add(foundTag);

            }
            taxonomy.Save(SaveMode.Flush);

            return saveTaxTags;
        }

        public IList<TaxonomyTag> ProcessTagList(int taxonomyId, TaxonomyTag parent, IList<string> tags, bool allowAdding)
        {
            IList<string> list = tags;
            Taxonomy tax = Taxonomy.Load(taxonomyId);
            List<Tag> saveTags = new List<Tag>();

                //Find or save tags
            foreach (string tag in list)
            {
                string trimmedTag = tag.Trim();
                IList<Tag> foundTag = GetTags(trimmedTag);
                if (foundTag.Count == 0 && allowAdding)
                {
                    Tag t = new Tag
                    {
                        Name = trimmedTag,
                        Slug = trimmedTag
                    };
                    t.Save();
                    saveTags.Add(t);
                }
                else if(foundTag.Count > 0)
                {
                    saveTags.AddRange(foundTag);
                }
            }

            return ProcessTagList(tax, parent, saveTags, allowAdding);
        }

        public ICollection<TaxonomyTag> RemoveTagFromList(int taxonomytagid, ICollection<TaxonomyTag> tags)
        {
            foreach (TaxonomyTag t in tags)
            {
                if (t.ID == taxonomytagid)
                {
                    tags.Remove(t);
                    break;
                }
            }
            return tags;
        }


        #endregion

        #region TaxonomyTags
        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Delete, true)]
        public void DeleteTaxonomyTag(TaxonomyTag taxonomy)
        {
            taxonomy.Delete();
            taxonomy.Save();
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Insert, true)]
        public int NewTaxonomyTag(TaxonomyTag taxonomy)
        {
            taxonomy.Save();
            return taxonomy.ID;
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, true)]
        public TaxonomyTag UpdateTaxonomyTag(TaxonomyTag taxonomy)
        {
            TaxonomyTag.Evict(taxonomy.ID);
            TaxonomyTag update = TaxonomyTag.Load(taxonomy.ID);
            With.Transaction.Execute(delegate
            {
                update.Description = taxonomy.Description;
                update.ParentTaxonomyTag = taxonomy.ParentTaxonomyTag;
                update.Slug = UrlHelper.FormatFriendly(taxonomy.Slug);
                update.ChildrenMutuallyExclusive = taxonomy.ChildrenMutuallyExclusive;
                update.IsVisible = taxonomy.IsVisible;
                update.IsSelectable = taxonomy.IsSelectable;
                update.Save();
            });
            return update;
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
        public IList<TaxonomyTag> GetTaxonomyTags()
        {
            return TaxonomyTag.Search(QrySearchTaxonomyTagsByTag.Query(false));
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
        public List<TaxonomyTag> GetTaxonomyTags(string taxonomyId, string sortExpression)
        {
        if (taxonomyId == "None")
                taxonomyId = "";
            var selectionList =
                from tag in TaxonomyTag.Search()
                where (string.IsNullOrEmpty(taxonomyId) ? true : tag.Taxonomy.ID+"" == taxonomyId)
                select tag;

            List<TaxonomyTag> list = new List<TaxonomyTag>(selectionList);

            if (list != null && sortExpression != String.Empty)
            {
                string[] sortOptions = sortExpression.Split(' ');
                if (sortOptions.Length > 0)
                {
                    string order = sortOptions.Length > 1 ? sortOptions[1] : "ASC";
                    GenericObjectComparer<TaxonomyTag> comparer = new GenericObjectComparer<TaxonomyTag>(sortOptions[0], order);
                    list.Sort(comparer);
                }
            }
            return list;
        }

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
        public List<TaxonomyTag> GetTaxonomyTags(string sortExpression)
        {
            List<TaxonomyTag> list = (List<TaxonomyTag>)TaxonomyTag.Search();
            if (list != null && sortExpression != String.Empty)
            {
                string[] sortOptions = sortExpression.Split(' ');
                if (sortOptions.Length > 0)
                {
                    string order = sortOptions.Length > 1 ? sortOptions[1] : "ASC";
                    GenericObjectComparer<TaxonomyTag> comparer = new GenericObjectComparer<TaxonomyTag>(sortOptions[0], order);
                    list.Sort(comparer);
                }
            }
            return list;
        }

        public TaxonomyTag GetTaxonomyTag(int taxonomyId, int tagId)
        {
            return TaxonomyTag.Fetch(QrySearchTaxonomyTagsByTag.Query(taxonomyId, tagId));
        }

        public TaxonomyTag GetTaxonomyTag(string slug)
        {
            return TaxonomyTag.Fetch(QryFetchTaxonomyTagBySlug.Query(slug));
        }

        public IList<TaxonomyTag> GetTaxonomyTags(int taxonomyID, bool attachedOnly)
        {
            return TaxonomyTag.Search(QrySearchTaxonomyTagsByTaxonomy.Query(taxonomyID));
        }

        public IList<TaxonomyTag> GetTaxonomyTags(int taxonomyID, int parentID)
        {
            return TaxonomyTag.Search(QrySearchTaxonomyTagsByTaxonomy.Query(taxonomyID, parentID, true));
        }

        public IList<TaxonomyTag> GetTaxonomyTagChildren(int parentID, bool attachedOnly)
        {
            return TaxonomyTag.Search(QrySearchTaxonomyTagsByParent.Query(parentID, attachedOnly));
        }

        public IList<TaxonomyTag> GetTopTaxonomyTagChildren(int parentID, int numberToGet)
        {
            return TaxonomyTag.Search(QrySearchTaxonomyTagStatisticsByParent.Query(parentID, numberToGet));
        }

        #endregion

        #region Page Taxonomy Tags

        [DataObjectMethodAttribute(DataObjectMethodType.Select)]
        public IList<TaxonomyTag> GetPageTaxonomyTags(int pageId)
        {
            Contentpage page = Contentpage.Load(pageId);
            if (page.TaxonomyTags != null)
            {
                return new List<TaxonomyTag>(page.TaxonomyTags);
            }
            else
                return new List<TaxonomyTag>();
        }

        [DataObjectMethodAttribute(DataObjectMethodType.Insert)]
        public TaxonomyTag NewPageTaxonomyTag(int pageId, TaxonomyTag tag)
        {
            Contentpage.Evict(pageId);
            With.Transaction.Execute(delegate
            {
                Contentpage page = Contentpage.Load(pageId);
                page.TaxonomyTags.Add(tag);
                page.Save();
            });
            return tag;
        }

        [DataObjectMethodAttribute(DataObjectMethodType.Delete)]
        public TaxonomyTag DeletePageTaxonomyTag(int pageId, TaxonomyTag tag)
        {
            Contentpage.Evict(pageId);
            With.Transaction.Execute(delegate
            {
                Contentpage page = Contentpage.Load(pageId);
                TaxonomyTag loadedTag = TaxonomyTag.Load(tag.ID);
                page.TaxonomyTags.Remove(loadedTag);
                page.Save();
            });
            tag.Delete();
            return tag;
        }

        #endregion

        
    }

    public static class TaggingControllerExtensions
    {
        /// <summary>
        /// Sorts a list of tags alphabetically
        /// </summary>
        public static List<TaxonomyTag> SortTags(this List<TaxonomyTag> list)
        {
            list.Sort((t1, t2) => string.Compare(t1.Slug, t2.Slug));
            return list;
        }
    }
}
